<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <input type="text">
    <script>
        // 一、递归函数
        // 1.概念：递归函数是一个直接或间接调用它本身，直到满足某种条件退回退出的函数。
        //        函数内部自己调用自己
        // 2.作用：用于迭代

        // 3.举例：
        // 计算阶乘： 4的阶乘=1*2*3*4=24

        // 方法一：
        // function number(num){
        //     let s=1;
        //     for(let i=1;i<=num;i++){
        //         s=s*i;
        //     }
        //     return s;
        // }
        // console.log(number(4));

        // 方法二：递归
        // function number(num){
        //     if(num==1){
        //         return 1;
        //     }else{
        //         return num*number(--num);//4*3*2*1
        //     }
        // }
        // console.log(number(4));

        // 斐波拉契数列：1 1 2 3 5 8 13 21
        // 方法一：
        // function Fb(num) {
        //     let a = 1;
        //     let b = 1;
        //     let temp;
        //     for (let i = 3; i <= num; i++) {
        //         temp = a;
        //         a = b;
        //         b = temp + b;
        //     }
        //     return b;
        // }

        // console.log(Fb(7));

        // 方法二：递归
        // let numCalc = function (i) {
        //     if (i == 1) {
        //         return 0;
        //     } else if (i == 2) {
        //         return 1;
        //     } else {
        //         return numCalc(i - 1) + numCalc(i - 2);
        //     }
        // }
        // console.log(numCalc(8)); //13


        // 二、高阶函数
        // （一）函数作为参数传递给另一个函数：回调函数
        // 1.排序：arr.sort()
        // 2.计时器：setInterval()和setTimeout()
        // 3.arr.every():全部结果是true，最终才是true
        // 4.arr.some():全部结果是false，最终才是false
        // 5.arr.filter():过滤，返回值是结果为true所组成的数组
        // 6.arr.find():查找
        // 7.arr.forEach():遍历
        // 8.arr.map():返回运行结果所组成的数组

        // （二）函数作为返回值
        // function foo(){
        //     let a=10;
        //     return function(){
        //         console.log(a);
        //     }
        // }
        // let f=foo();

        // 三、高阶函数的实际应用
        // 当函数被频繁触发的时候，浏览器有可能会出现性能问题，函数防抖和函数节流就是为了优化性能问题
        // 函数防抖和函数节流的核心就是阻止函数被频繁触发

        // 重绘和重排
        // 1.重绘：发生在元素的可见外观被改变，但是并没有影响到布局的时候。
        // 比如修改颜色等

        // 2.重排：发生在元素尺寸和布局方式上的改变，比如元素尺寸大小改变，显示或者隐藏，布局改变等
        //        页面最开始加载的时候，就会发生重排

        // 关系：重排一定会引发重绘，重绘不一定会引发重排
        // 页面性能优化：尽可能的减少重排
        // 引发重排的情况：任何页面布局和几何属性的改变都会引发重排
        // （1）页面渲染初始化（无法避免）
        // （2）添加或者删除可见的DOM元素
        // （3）元素位置的改变，或者使用动画
        // （4）元素尺寸的改变：大小、内外边距、边框
        // （5）浏览器窗口尺寸的变换
        // （6）填充内容的改变，比如文本的改变或者图片大小改变而引起的计算值宽度和高度的改变

        // 降低重排和重绘的方法：
        // （1）避免频繁的使用style，而是采用class增加或者删除的方式修改样式
        // （2）将动画效果应用到position属性为absolute或者fixed元素上
        // （3）可以先将元素设置为display：none,操作结束后再把它显示出来，
        // 因为在display：none的元素上进行DOM操作不会引发重排和重绘
        // （4）使用文档碎片document.createDocumentFragment进行批量的DOM操作
        // （5）对于resize、scroll等事件进行节流或者防抖处理
        // （6）避免频繁读取会引发重排或者重绘的属性，如果确实需要多次使用，就用一个变量缓存起来
        // （7）利用CSS3的transform、opacity这些属性可以实现合成的效果

        // （一）函数防抖：将若干需要立即执行的函数调用合成一次调用，并在给定的时间过去之后，或者连续事件完全触发完成之后，调用一次函数
        // let debounce = function (fn, interval) {
        //     let _self = fn, //保存需要被延迟执行的函数引用
        //         timer, //定时器
        //         firstTime = true; //是否是第一次调用
        //     return function () {
        //         if (firstTime) //如果是第一次调用，不需延迟执行
        //         {
        //             _self.apply(null, arguments);
        //             return firstTime = false;
        //         }
        //         if (timer) //如果定时器还在，说明前一次延迟执行还没有完成
        //         {
        //             return false;
        //         }
        //         timer = setTimeout(function () { // 延迟一段时间执行 clearTimeout(timer);
        //             timer = null;
        //             _self.apply(null, arguments);
        //         }, interval || 500);
        //     };
        // };


        // 例1：监听可视窗口大小变化

        // window.onresize = debounce(function () {
        //     console.log(innerWidth);
        // }, 1000);

        // 例2：监听输入框输入的内容:当用户停止输入2秒之后，再获取输入框中的内容
        // let input=document.getElementsByTagName("input")[0];
        // input.oninput=debounce(function(){
        //     console.log(input.value);
        // },2000);


        // (二)函数节流：间隔指定的时间，触发一次函数，可以理解为缩减执行频率

        function throttle(cb, wait) {
            let arg = null;
            let context = null;
            let previous = 0;
            return function () {
                context = this;
                arg = arguments;
                let now = new Date().getTime();
                if (now - previous > wait) {
                    //执行
                    // cb && cb.apply(context, arg);
                    // 相当于
                    if(cb){
                        cb.apply(context,arg);
                    }
                    //重新记录上一次的事件
                    previous = now;
                }
            }
        }

        // let i=1;
        // setInterval(function(){
        //     console.log(i++);
        // },100);


        // 每间隔100毫秒数字+1，每间隔1000毫秒，输出一次数字
        // let i=1;
        // let test=throttle(function(){
        //     console.log(i++);
        // },1000);
        // setInterval(function(){
        //     test(i++);
        // },100);

        // 总结：
        // 1.浏览器工作原理
        // 2.立即执行函数
        // 3.js引擎解析js代码的详细过程：执行上下文栈、全局执行上下文、函数执行上下文、VO\GO\AO
        // 4.闭包：概念、形成闭包的条件、闭包的优缺点
        // 5.递归函数
        // 6.高阶函数:函数作为参数和返回值
        // 7.函数节流和函数防抖
        // 8.重排和重绘
    </script>
</body>

</html>